package org.pwwong.scalautils.signals

import org.pwwong.scalautils.event._
import org.pwwong.scalautils.time._

import scala.collection.immutable.{EmptySet,Set}

object Predef {
  
  implicit def signalToEvents[T](value:Signal[T]):Event[T] = value.onChange
  //implicit def valueToSignal[T](value:T):Signal[T] = ConstantSignal[T](value)
  //implicit def nullToSignal[T](nullValue:Null):Signal[T] = new ConstantSignal[T](null.asInstanceOf[T])
  
  // Carries the information necessary to build an AnimatedSignal
  protected class EvalSignalBuilder[T](val evaluator:()=>T) {
    protected[Predef] var resolution:Option[Duration] = None
    protected[Predef] var dependencies:Option[Set[Event[_]]] = None
    
    def every(res:Duration) = {resolution = Some(res); this}
    def when(depEvs:Event[_]*) = {dependencies = Some(Set(depEvs:_*)); this}
    def toSignal:Signal[T] = builderToEvalSignal[T](this)
        
    def isComplete:Boolean = (resolution != None || dependencies != None)
    def incompleteMessage:String = if(!isComplete) "Resolution or atleast on triggering Event or Signal must be specified" else "?"
  }
  
  // Creates an AnimatedSignalBuilder
  def eval[T](evaluator: =>T) = new EvalSignalBuilder[T]( ()=>evaluator )
  
  implicit def builderToEvalSignal[T](builder:EvalSignalBuilder[T]):Signal[T] = {
    require(builder isComplete, builder incompleteMessage)
    new EvalSignal[T]( builder.evaluator,
                       (builder.dependencies match {
                         case Some(deps) => deps
                         case None => new EmptySet[Event[_]]
                       }) ++
                       (builder.resolution match {
                         case Some(res) => Set[Event[_]](TimedSignal(res,true).onChange)
                         case None => new EmptySet[Event[_]]
                       })            
    )
  }
  
  def onChanges[T](sigs:Signal[T]*)(ref:AnyRef)(runMe:T=>Unit){
    sigs.foreach( _.onChange(ref)(runMe) )
  }
  def onAnyChanges(sigs:Signal[_]*)(ref:AnyRef)(runMe: =>Unit){
    sigs.foreach( _.onChange(ref){tmp => runMe} )
  }
}
